import os
import datetime
import uuid
from typing import Optional, Dict, Any

from jose import JWTError, jwt
from dotenv import load_dotenv

# 加载环境变量
load_dotenv()

# JWT配置
SECRET_KEY = os.getenv("JWT_SECRET_KEY", "your-secret-key-here")
ALGORITHM = os.getenv("JWT_ALGORITHM", "HS256")
# 设置token过期时间为1天
ACCESS_TOKEN_EXPIRE_DAYS = 1
ACCESS_TOKEN_EXPIRE_SECONDS = ACCESS_TOKEN_EXPIRE_DAYS * 24 * 60 * 60
# 设置token刷新阈值为23小时（小于过期时间）
TOKEN_REFRESH_THRESHOLD_HOURS = 23
TOKEN_REFRESH_THRESHOLD_SECONDS = TOKEN_REFRESH_THRESHOLD_HOURS * 60 * 60


def encode_token(data: dict, expires_delta: Optional[datetime.timedelta] = None) -> str:
    """
    生成jwt的token，默认过期时间为1天
    :param data: jwt加密的数据
    :param expires_delta: 过期时间
    :return: 生成的token
    """
    to_encode = data.copy()
    # 添加token_id，用于在Redis中标识token
    token_id = str(uuid.uuid4())
    to_encode.update({"token_id": token_id})
    
    # 设置过期时间
    expire = datetime.datetime.utcnow() + (
        expires_delta or datetime.timedelta(days=ACCESS_TOKEN_EXPIRE_DAYS)
    )
    to_encode.update({"exp": expire})
    
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)


def decode_token(token: str) -> Optional[str]:
    """
    验证并返回用户名
    无效则返回False
    """
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username = str(payload.get("username"))
        if username is None:
            raise JWTError
        return username
    except JWTError:
        return None


def verify_token(token: str) -> Optional[Dict[str, Any]]:
    """
    验证token并返回payload
    :param token: JWT token
    :return: token payload或None
    """
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        return None


def should_refresh_token(payload: Dict[str, Any]) -> bool:
    """
    检查token是否需要刷新
    如果token剩余有效期小于刷新阈值，则返回True
    """
    exp = payload.get("exp")
    if not exp:
        return False
    
    # 计算token剩余有效期
    now = datetime.datetime.utcnow().timestamp()
    remaining_seconds = exp - now
    
    # 如果剩余时间小于刷新阈值，则需要刷新
    return remaining_seconds < TOKEN_REFRESH_THRESHOLD_SECONDS


if __name__ == '__main__':
    token = encode_token({
        "username": "li.jianguo"
    })
    print(token)
    print(decode_token("token"))
